#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <memory>
#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"

namespace My_ThreadPool
{
    using namespace My_Mutex;
    using namespace My_Log;
    using namespace My_Cond;
    using namespace My_Thread;

    using thread_t = std::shared_ptr<Thread>;

    const static int defaultnum = 5;

    void DefaultTest()
    {
        while (true)
        {
            LOG(LogLevel::DEBUG) << "Test......";

            sleep(1);
        }
    }

    template <class T>
    class ThreadPool
    {
    private:
        bool IsEmpty() { return _ptasks.empty(); }

        void HanderTask(std::string name)
        {
            T t;
            LOG(LogLevel::INFO) << "线程: " << name << "执行HanderTask方法";
            while (true)
            {
                {
                    LockGuard lockguard(_lock);
                    while (IsEmpty() && _isrunning)
                    {
                        _wait_num++;
                        _cond.Wait(_lock);
                        _wait_num--;
                    }

                    if (IsEmpty() && !_isrunning)
                        break;

                    t = _ptasks.front();
                    _ptasks.pop();
                }

                t(name);
            }
            LOG(LogLevel::INFO) << "线程: " << name << "退出HanderTask方法";
        }

        ThreadPool(const ThreadPool &) = delete;
        ThreadPool<T> &operator=(const ThreadPool &) = delete;

        ThreadPool(int num = defaultnum) : _num(num), _isrunning(false)
        {
            for (int i = 0; i < _num; i++)
            {
                _threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask, this, std::placeholders::_1)));
                LOG(LogLevel::INFO) << "创建线程： " << _threads.back()->Name() << "...Success";
            }
        }

    public:
        static ThreadPool<T> *getinstance()
        {
            if (instance == NULL)
            {
                LockGuard lockguard(mutex);
                if (instance == NULL)
                {
                    LOG(LogLevel::INFO) << "单例首次被执行，需要加载对象...";
                    instance = new ThreadPool<T>();
                }
            }
            return instance;
        }

        void Equeue(T t)
        {
            LockGuard lockguard(_lock); // 加锁
            if (!_isrunning)
                return;
            _ptasks.push(t);
            if (_wait_num)
                _cond.Weak();
        }
        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true;
            for (auto &t : _threads)
            {
                t->Start();
                LOG(LogLevel::INFO) << "启动线程： " << t->Name() << "...Success";
            }
        }
        void Wait()
        {
            for (auto &t : _threads)
            {
                t->Jion();
                LOG(LogLevel::INFO) << "线程: " << t->Name() << "回收";
            }
        }
        void Stop()
        {
            if (_isrunning)
            {
                _isrunning = false;
                if (_wait_num)
                    _cond.WeakAll(); // 如果有线程在可变参数下等待，唤醒所有线程，把没有执行完成的任务（如果有）去执行
            }
        }
        ~ThreadPool() {}

    private:
        std::vector<thread_t> _threads; // 这里储存的是一个一个的指向Thread的智能指针
        int _num;                       // 线程个数
        std::queue<T> _ptasks;          // 任务的指针队列

        Mutex _lock;
        Cond _cond;
        int _wait_num;

        bool _isrunning; // 线程池目前的工作状态

        static ThreadPool<T> *instance;
        static Mutex mutex;
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::instance = NULL;
    template <typename T>
    Mutex ThreadPool<T>::mutex; // 只用来保护单例
}